#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
using namespace std;
/*
    线程同步：
            多个线程之间按照一定的顺序执行

    同步机制常用于生产者消费者模型：
            消费者任务要想执行，必须先执行生产者线程，多个任务有顺序执行

    无名信号量：
        本质上也是一个特殊的临界资源，内部维护了一个value值，当某个进行想要执行之前，
        先申请该无名信号量的value资源，如果value值大于0，则申请资源函数接触阻塞，
        继续执行后续操作。如果value值为0，则当前申请资源函数会处于阻塞状态，
        直到其他线程将该value值增加到大于0，当前线程才会被唤醒，继续执行后续操作


API:
1、创建无名信号量：只需定义一个sem_t 类型的变量即可
        sem_t sem;

 2、初始化无名信号量
       #include <semaphore.h>

       int sem_init(sem_t *sem, int pshared, unsigned int value);
       功能：初始化无名信号量，最主要是初始化value值
       参数1：无名信号量的地址
       参数2：判断进程还是线程的同步
                0：表示线程间同步
                非0：表示进程间同步，需要创建在共享内存段中
        参数3：无名信号量的初始值
        返回值：成功返回0，失败返回-1并置位错误码

3、申请无名信号量的资源（P操作）
       #include <semaphore.h>

       int sem_wait(sem_t *sem);
       功能：阻塞申请无名信号量中的资源，成功申请后，会将无名信号量的value进行减1操作，如果当
前无名信号量的value为0，则阻塞
       参数：无名信号量的地址
       返回值：成功返回0，失败返回-1并置位错误码

4、释放无名信号量的资源（V操作）
       #include <semaphore.h>

       int sem_post(sem_t *sem);
       功能：将无名信号量的value值增加1操作
       参数：无名信号量地址
       返回值：成功返回0，失败返回-1并置位错误码

5、销毁无名信号量
       #include <semaphore.h>
       int sem_destroy(sem_t *sem);
       功能：销毁无名信号量
       参数：无名信号量地址
       返回值：成功返回0，失败返回-1并置位错误码
*/
// 1.创建无名信号量
sem_t sem;

void *producer(void *arg)
{
    int n = *(int *)arg;
    for (int i = 1; i <= n; i++)
    {
        printf("生产了一个资源：%d,累死了\n", i);
        sem_post(&sem); // 释放资源
        sleep(1);       // 防止生产者线程执行太快导致cpu一直运行这个线程
    }

    return NULL;
}

void *consumer(void *arg)
{

    int n = *(int *)arg;
    while (n)
    {
        sem_wait(&sem); // 申请资源(因为初值为0,所以生产者线程会先执行)
        printf("消费了一个资源，爽死了\n");
        n--;
        // 不需要像生产者线程一样sleep,因为当信号量为0时候就阻塞了
    }
    return NULL;
}

int main()
{
    // 2.初始化无名信号量
    sem_init(&sem, 0, 0);
    // 参数二的0表示线程间同步
    // 参数三的0表示信号量初始值为0,从而决定那个线程先执行

    pthread_t tid1, tid2;
    int producerNum = 5;
    pthread_create(&tid1, NULL, producer, &producerNum);
    pthread_create(&tid2, NULL, consumer, &producerNum);
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    // 3.销毁无名信号量
    sem_destroy(&sem);
    printf("生产者线程和消费者线程执行完毕\n");
    return 0;
    /*
    当有多个线程都需要同步时候
    就需要创建多个无名信号量，每个信号量管理一个线程
    就像多进程中多个进程需要同步时候，使用信号集实现的机制一样
    */
}